﻿namespace TomatoBreak.UnitSpecs.Routing
{
    using System;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Routing;

    using NSubstitute;

    public class RouteExecuter
    {
        private const string AppPathModifier = "/$(SESSION)";

        public RouteExecuter(RouteCollection routes)
        {
            Routes = routes;
        }

        protected RouteCollection Routes { get; private set; }

        public RouteMatchingResult Get(string url)
        {
            var routeData = GetRouteData(url, HttpVerbs.Get);

            return CreateResult(routeData);
        }

        public RouteMatchingResult Post(string url)
        {
            var routeData = GetRouteData(url, HttpVerbs.Post);

            return CreateResult(routeData);
        }

        public RouteMatchingResult Put(string url)
        {
            var routeData = GetRouteData(url, HttpVerbs.Put);

            return CreateResult(routeData);
        }

        public RouteMatchingResult Delete(string url)
        {
            var routeData = GetRouteData(url, HttpVerbs.Delete);

            return CreateResult(routeData);
        }

        private static RouteMatchingResult CreateResult(RouteData routeData)
        {
            return (routeData == null) ? null : new RouteMatchingResult(routeData);
        }

        private static HttpContextBase CreateHttpContext(string url = null, HttpVerbs? httpVerb = null)
        {
            var httpRequest = Substitute.For<HttpRequestBase>();

            if ((url != null) && !url.StartsWith("~/"))
            {
                httpRequest.Url.Returns(new Uri(url));
            }

            if (httpVerb != null)
            {
                httpRequest.HttpMethod.Returns(httpVerb.ToString().ToUpperInvariant());
            }

            httpRequest.AppRelativeCurrentExecutionFilePath.Returns(url);
            httpRequest.ApplicationPath.Returns("/app/");

            var httpResponse = Substitute.For<HttpResponseBase>();
            httpResponse.ApplyAppPathModifier(Arg.Any<string>()).Returns(x => ((string)x[0]).Contains(AppPathModifier) ? (string)x[0] : AppPathModifier + (string)x[0]);

            var httpContext = Substitute.For<HttpContextBase>();

            httpContext.Request.Returns(httpRequest);
            httpContext.Response.Returns(httpResponse);

            return httpContext;
        }

        private RouteData GetRouteData(string url, HttpVerbs httpVerb)
        {
            var httpContext = CreateHttpContext(url, httpVerb);
            var routeDate = Routes.GetRouteData(httpContext);

            return routeDate;
        }
    }
}